<?php

class eRDF_parser{

	private $uri;
	public 	$triples = array();
	private $schemas = array();
	private $errors = array();
	private $doc;
	private $xpath;
		
	function __construct($uri, $schemas=false)
	{
		$this->uri = $uri;
		$this->doc = new DOMDocument();
		
		if($xml = file_get_contents($uri) )
		{
			$this->doc->loadHTML($xml);
			$this->xpath = new DOMXPath($this->doc);
			if($schemas) $this->schemas = $schemas;
		}
		else
		{
			$this->errors[]= 'Couldn\'t fetch document';
		}

	}
	
	public function parse($get_labels=false)
	{
		$this->get_schemas();
		$this->meta_elements();
		$this->link_elements_rel();
		$this->link_elements_rev();
		$this->anchors_with_rel();
		$this->anchors_with_rev();
		$this->elements_with_class();
		if($get_labels) $this->labels();
		return array(
					'result'=> $this->get_triples(),
					'error' => $this->get_errors(),
					);
	}
	
	public function get_errors()
	{
		return $this->errors;
	}
	
	public function do_owl_sameAs()
	{
		for($x=0;$x<count($this->triples);$x++)
		{
			$t = $this->triples[$x];
			if ($t['p'] == 'http://www.w3.org/2002/07/owl#sameAs')
			{
				$new_s = $t['o'];
				$old_s = $t['s'];
				unset($this->triples[$x]);
				for($y=0;$y<count($this->triples);$y++)
				{
					$triple =& $this->triples[$x];
					if($triple['s']==$old_s) $triple['s'] = $new_s;
					if($triple['o']==$old_s) $triple['o'] = $new_s;
				}
			}
		}
		
		return $this->get_triples();
	}

	public function get_schemas()
	{
		if(empty($this->schemas))
		{
			$links  = $this->xpath->query('//link[contains(@rel, \'schema.\')]');
			foreach($links as $link)
			{

				$rels = $link->getAttribute('rel');
				
				
				foreach(explode(' ',$rels) as $rel)
				{
					if(strpos($rel, 'schema.')===0)
					{
						$href = $link->getAttribute('href');
						$trailing_char = substr($href,(strlen($href)-1) );
						if($trailing_char!='#' && $trailing_char!='/') $href.='#';
						$this->schemas[substr($rel,7)]= $href;
					}
				}
			}
		}


		return $this->schemas;
	}

	
	
	public function get_triples()
	{
		return $this->triples;
	}

	public function add_triple($s,$p, $o, $o_lang=false, $p_type='dt')
	{

		$triple = array('s'=>$s,'p'=>$p, 'p_type'=>$p_type, 'o'=>$o);	
		if($o_lang) $triple['o_lang'] = $o_lang;
		$this->triples[]= $triple;

		return $triple;
	}

	private function nearest_id($el)
	{
		$nearest = $this->xpath->query('ancestor::node()[@id][1]', $el);		
		return ($el = $nearest->item(0))? $this->base_uri().'#'.$el->getAttribute('id') : $this->base_uri();
	}
	
	public function get_lang($el)		
	{
		return ($lang = $el->getAttribute('lang'))? $lang : false;
	}

	private function base_uri()
	{
		return ($base = $this->xpath->query('//base[1]')->item(0))? $base->getAttribute('href') : $this->uri;	
	}
	
	public function attname_to_uri($att_name)
	{
		$schemas = $this->get_schemas();
		foreach(array('.','-') as $separator)
		{
			//check attname contains separator
			if (strpos($att_name,$separator)!==false)
			{
				 $arr =  explode($separator,$att_name);
				
				//if there was a leading hyphen, first item will be empty, so get rid of it
				if ( empty($arr[0])) array_shift($arr);
				
				$prefix = $arr[0];
				
				//now get the term after the separator
				array_shift($arr);
				$term = implode($separator, $arr);
				break;
			}
		}
		
		//if no separators were found, this isn't an erdf attname		
		
		if ( isset($prefix) && isset($schemas[$prefix])  )
		{
			$namespace =  $schemas[$prefix];
			return $namespace.$term;
		}
		else return false;
			
	}

	public function local_uri_to_global($uri)
	{
		if(strpos($uri,'http://')===0)
		{
			return $uri;
		}
		else
		{
			$uri_parts = explode('/',$this->base_uri());
			array_pop($uri_parts);
			$base_uri = implode('/',$uri_parts);
			return $base_uri.'/'.$uri;	
		}
	}
	
	
	public function check_profile()
	{
		$profile = $this->xpath->query('//@profile[contains(.,\'http://purl.org/NET/erdf/profile\')]');
		return $profile->length;
	}

	/* Triple Generation Methods according to rules at: 
		http://research.talis.com/2005/erdf/wiki/Main/SummaryOfTripleProductionRules
	*/

	public function meta_elements()
	{

		$metas = $this->xpath->query('//head/meta[@name]');
		$meta_triples = array();
		foreach($metas as $meta)
		{
			if($predicate = $this->attname_to_uri($meta->getAttribute('name')))
			{
				$p_type='dt';
				$o_lang = $this->get_lang($meta);
				$meta_triples[] = $this->add_triple($this->base_uri(), $predicate, $meta->getAttribute('content'), $o_lang, $p_type);
			}
		}
		return $meta_triples;
	}

	function link_elements_rel()
	{
				
		$links = $this->xpath->query('//head/link[@rel][@href]');
		$link_triples = array();
		foreach($links as $link)
		{
			if($predicate = $this->attname_to_uri($link->getAttribute('rel')))
			{
				$p_type='obj';
				$object = $this->local_uri_to_global($link->getAttribute('href'));
				$link_triples[] = $this->add_triple($this->base_uri(), $predicate, $object, false, $p_type);
			}
		}
		return $link_triples;
	}
	
	function link_elements_rev()
	{

		$links = $this->xpath->query('//head/link[@rev][@href]');
		$link_triples = array();
		foreach($links as $link)
		{
			if($predicate = $this->attname_to_uri($link->getAttribute('rev')))
			{
				$p_type='obj';
				$subject = $this->local_uri_to_global($link->getAttribute('href'));
				$link_triples[] = $this->add_triple($subject, $predicate, $this->base_uri(), false, $p_type);
			}
		}
		return $link_triples;
	}

	function elements_with_class()
	{
		$class_triples = array();
		$els = $this->xpath->query('//*[contains(@class, "-")]');
		foreach($els as $el)
		{
			$classnames = explode(' ', $el->getAttribute('class'));
			foreach($classnames as $classname)
			{

				$subject = $this->nearest_id($el);

				if(strpos($classname,'-'))//only property style classnames
				{
					if($predicate = $this->attname_to_uri($classname))
					{
						switch(true)
						{
							case $object = $el->getAttribute('src') : $object = $this->local_uri_to_global($object); 
							$p_type='obj';
							break;
							case $object = $el->getAttribute('id') : $object = $this->base_uri().$object;
							$p_type='obj';
								break;
							case $object = $el->getAttribute('title') : 
								$p_type='dt';
								break;
		
							case $object = $el->textContent : 
								$p_type='dt';
								break;
						}
						
						$o_lang = $this->get_lang($el);
						$class_triples[] = $this->add_triple($subject,$predicate,$object, $o_lang, $p_type);

					}
				}
				elseif(strpos($classname,'-')===0 && $object = $this->attname_to_uri($classname))
				{ //rdf:type style classnames
					$subject = $this->base_uri().'#'.($el->getAttribute('id'));
					$predicate = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type';
					$p_type='obj';
					$class_triples[] = $this->add_triple($subject, $predicate, $object, false, $p_type);					
				}
			}
		}

		return $class_triples;
	}


	function anchors_with_rel()
	{
		$anchors = $this->xpath->query('//a[@rel][@href]');
		$anchor_triples = array();
		foreach($anchors as $anchor)
		{
			$relnames = explode(' ', $anchor->getAttribute('rel'));
			foreach($relnames as $relname)
			{
				
				if(($this->attname_to_uri($relname)) && strpos($relname,'-'))
				{
					$predicate = $this->attname_to_uri($relname);
					$object = $this->local_uri_to_global($anchor->getAttribute('href'));
					$p_type='obj';
					$anchor_triples[] = $this->add_triple($this->nearest_id($anchor), $predicate, $object, false, $p_type);
				}
			}
		}
		return $anchor_triples;

	}

	function anchors_with_rev()
	{

		$anchors = $this->xpath->query('//a[@rev][@href]');
		$anchor_triples = array();
		foreach($anchors as $anchor)
		{
			$revnames = explode(' ', $anchor->getAttribute('rev'));
			foreach($revnames as $revname)
			{
				if($predicate = $this->attname_to_uri($revname) )
				{
					if( strpos($revname,'-'))
					{
						$subject = $this->local_uri_to_global($anchor->getAttribute('href'));
						$p_type='obj';
						$anchor_triples[] = $this->add_triple($subject, $predicate, $this->nearest_id($anchor), false, $p_type );
					}
				}
			}
		}
		return $anchor_triples;
	}

	function labels()
	{
		$label_triples = array();
		$els = $this->xpath->query('//a[@href]|//img[@src]');
		foreach($els as $el)
		{
			$subject = ($src = $el->getAttribute('src'))? $this->local_uri_to_global($src) : $this->local_uri_to_global($el->getAttribute('href'));
			$predicate = 'http://www.w3.org/2000/01/rdf-schema#label';
			$object = ($title = $el->getAttribute('title'))? $title :  $el->textContent;
			$o_lang = $this->get_lang($el);
			$p_type='dt';
			$label_triples[] = $this->add_triple($subject, $predicate, $object, $o_lang, $p_type);
		}
		return $label_triples;
	}
	
	/* Output Formats */
	
	public function to_n3()
	{
		$n3 = '';
		foreach($this->triples as $t)
		{
			if($t['p_type']=='dt') 
			{
				$o = '"'.$t['o'].'"';
				if(isset($t['o_lang'])) $o.= ($lang = $t['o_lang'])? '@'.$lang : '';
			}
			else
			{
				$o = "<{$t['o']}>";
			}
			
			$n3.=<<<_N3_

<{$t['s']}> <{$t['p']}>  $o .

_N3_;
		}
		
		return $n3;
		
	}

			
}


?>
